BSAVE (graphics image format)

A BSAVE Image (aka "BSAVED Image") as it is referenced in a graphics program is an image file format created usually by saving raw video memory to disk (sometimes but not always in a BASIC program using the BSAVE command).[1]

This format was in general use when the IBM PC was introduced. It was also in general use on the Apple II in the same time period. The Commodore 128 followed with the addition of the BSAVE and BLOAD Commands a short time later.

On the IBM, BSaved graphics and text images could be created for any video mode, with more complexity for the newer modes. On the Apple II and Commodore 128 BSaved Graphics were generally all that was used.

Contents

Typical file format

The BSAVED format is a device-dependent raster image format; the file header stores information about the display hardware address, and the size of the graphics data. The graphics data follows the header directly and is stored as raw data in the format of the native adapter's addressable memory.

There is no file compression, and therefore these load very quickly and without much programming when displayed in native mode.

No additional information such as (screen resolution, color depth and palette information, bit planes and so on) is stored. Video adapters were simple when this format was in wide use and the other information to load these could usually be inferred by programs that loaded these.

Origin

The BASIC programming language was shipped as part of the operating system on the first IBM PCs, Apple and Commodore 8-bit (like Commodore 64/128) computers. On computers that did not start up in BASIC, BASIC was loaded by running a program called an interpreter. The user could then type BASIC commands in "immediate mode" or by creating and/or running a numbered BASIC program within the interpreter.

One of the commands that early BASIC offered was BSAVE (Binary Save) and another (complementary) command was BLOAD (Binary Load). Using the BSAVE command, an addressable area and length of memory could be saved to disk as a named file (referred to as an "Image").[1] This "Image" of saved memory could then be reloaded from disk into addressable memory later with the BLOAD command.[2] If the BSAVEd image contained program code it could be executed, if data it could be used again, and if the BSAVEd image contained graphics it could be viewed. The video area of memory was addressable.

The PUT and GET commands were used in addition to the BSAVE and BLOAD commands on the IBM PC to allow "clips" of the screen (or the entire screen) to be pre-formatted for BSAVE and BLOAD. These commands added image height and width to the BSAVE format, and were later carried over into the C programming language by some compiler vendors for the MS-DOS platform as the putimage() and getimage() run-time library functions. PUT and GET allowed display modifier verbs which resembled functions in the Windows Graphical Device Interface (GDI) used by programmers later.

Microsoft evolved and produced the BASIC interpreters that were bundled with the IBM PC, Apple II, and Commodore 128, and included the ability to BSAVE and BLOAD RAM images on all 3 platforms. While it is not clear whether or not Microsoft and its founder Bill Gates originated the BSAVE format they can be clearly credited with providing continued support for the BSAVEd Graphics Image throughout the history of its use by making it accessible to all users of these platforms and by completely documenting its use.

The BSAVE format of that time can be compared to some intents and purposes to the Windows BMP and DIB that came later.

Historical use

It was generally more common for computer users of the day (most who knew how to program in BASIC to some degree) to use the BLOAD command to load a graphics image that had been BSAVED than to load a BSAVED executable or data image.

Most early drawing programs allowed their graphics images to be BSAVED, making them easily available by an average user to be BLOADED back into video memory and viewed in a simple external program written in BASIC.

Recent use IBM PC

Common use of BSAVED images in graphics programs continued well into the 1990s but their use was primarily limited to users of programs like the Freeware program PicEM and the Shareware program VGACAD (which saved the MCGA display to a BSAVED file format called BLD BLoaDablepicture), and by beginning programmers and enthusiasts.

With the passing of MS-DOS so did the use of DOS programs that saved in the BSAVED format. Their use by programmers has stopped because the BLOAD command is no longer supported in modern programming languages which discourage accessing video memory directly.

Specifications IBM PC

CGA specification

CGA memory starts at memory segment B800h offset 0. Up to 16K of memory is available for video.

The amount of memory used for display depends on the video mode selected. A graphics screen requires 16000 bytes of memory and an 80 x 25 text screen requires 4000 bytes. A 40 x 25 text screen requires 2000 bytes.

The 3 common video modes are monochrome graphics, 4-color graphics or 80 column x 25 row color text.

A low-resolution 160 x 100 x 16 color graphics mode unofficially called "XCGA" and not supported in BIOS (interrupt 10h) also existed and had limited popularity amongst enthusiasts for a while. Technically this mode worked like color text mode. (see Color Graphics Adapter.)

40 column text mode was not generally used for BSAVED images.

Text

80 column text is stored in 4 pages of 4000 bytes each. Generally only page 1 was used for BSAVED text images. Each character in an 80 column x 25 row text screen is stored in a contiguous byte array of character, attribute pairs of 2 bytes per text character. The attribute byte stores the foreground color in the low nibble and the background color and blink attribute in the high nibble. The colors 0-16 correspond to the colors offered in text mode by the CGA.

These could be cross-loaded to a low-end monochrome text video display with only 4K of memory with varying degrees of success since the color attributes on monochrome displayed differently.

The file extension that became popular for the BSaved text screen format was .BSV.

In the BBS days before the Internet was widely used, many Sysops used a program called TheDraw© from TheSoft Programming Services in Fremont, CA as the tool-of-choice to design and build user interface screens. Programmers used TheDraw© to design text-based user interfaces, or to edit screens that had been captured from other text programs, and then often would display these edited screens in their own programs, or as slideshows for proof-of-concept and so-forth. TheDraw© saved in various formats including BSAVED with the default file extension of .BSV.

Header

The following C language source code documents the header and tailer in a BSAVED text image:

/* a Microsoft compatible bsaved memory text image format descriptor */
unsigned char BSV_header[7]={
 
    '\xfd',          /* ID Flag = file descriptor identifier bsaved file */
 
    '\x00', '\xb8',  /* base address     = LSB | MSB original segment    */
    '\x00', '\x00',  /* offset from base = LSB | MSB original offset     */
 
    '\xA0', '\x0F'   /* data size = LSB | MSB of bytes to be loaded +    */
    };
 
unsigned char BSV_image[4000];
 
unsigned char BSV_tailer[1]={
    '\x1A'                      /* traditionally used by BASIC */
    };                          /* as a terminator */
Example

By contrast the following tiny GWBASIC program demonstrates how easy it was to load these in BASIC.

1  DEF SEG=&HB800
2  KEY OFF
3  CLS
4  FILES "*.BSV"
5  INPUT"Enter Name of Image To Load. <Blank Ends> : ",A$
10 IF A$="" THEN SYSTEM
30 BLOAD A$,0
40 A$=INPUT$(1)
50 GOTO 3

Graphics

The CGA Video Card (and other IBM PC video cards which support CGA which until recently were almost all) has two interleafs when in monochrome or 4-color Graphics mode. Visible memory is 16000 bytes. There is 192 bytes of unused data between the first and second interleaf, and 192 bytes of unused data following the second interleaf. The byte array is identical for either mode.

Typical variations

File Size 16392 bytes Header Size 7 bytes First Interleaf 8000 bytes Unused 192 Bytes Second Interleaf 8000 bytes Unused 192 Bytes Tailer Size 1 byte

Variations on the above include a smaller BSaved file format that does not load the unused memory after the second interleaf, nor the traditional trailer byte 0x1a (CPM EOF). This resulted in a slight saving of disk space.

File Size 16199 bytes Header Size 7 bytes First Interleaf 8000 bytes Unused 192 Bytes Second Interleaf 8000 bytes

A variation of the BSAVED CGA Image used by the earliest version of PCPaint stored a signature followed by a 2 byte palette index in the unused area directly following the first interleaf.

BSAVED CGA Images were usually saved with a .PIC extension.

Pixel data

Monochrome data is stored as 1 bit per pixel with pixel(0,0) (x,y) being the high bit in the first byte and pixel(0,7) being the low bit in the first byte. The horizontal resolution for a monochrome CGA image is 640 pixels.

Color data is stored as 2 bits per pixel with pixel(0,0) (x,y) being the 2 highest bits in the first byte and pixel(0,3) being the 2 lowest bit in the first byte. The horizontal resolution for a monochrome CGA image is 640 pixels. The nominal color values are either BLACK, CYAN, MAGENTA, WHITE or BLACK, GREEN, RED, and ORANGE in color order depending on which of the two palettes was selected, with variations on border color (color 0). A third palette was available on some cards as well with nominal values of BLACK, CYAN, RED, WHITE. The horizontal resolution for a monochrome CGA image is 320 pixels.

The interleaf breaks on 80 byte boundaries which means that byte[80] is displayed starting at pixel(2,0), and conversely byte[8192] is displayed starting at pixel(1,0), and so it goes. Both color and monochrome have a vertical resolution of 200 scanlines.

Cross-loading


Because the monochrome and color images could be cross-loaded, a color image displayed in monochrome would be naturally dithered because of the bit alteration provided by the bit pairs in colors 1 and 2. Color 0 was still BLACK and color 3 was still WHITE. This dithering was fairly good for printouts of color images on the black-and-white printers of the day.

Monochrome images displayed in color did not do so well. The aliasing of pixels that were not paired on bit boundaries created CYAN and MAGENTA anomalies which usually looked terrible.

Header

The following C language source code documents the header and tailer in a BSAVED graphics image:

/* a Microsoft compatible bsaved memory image format descriptor */
unsigned char PUT_header[7]={
 
    '\xfd',          /* ID Flag = file descriptor identifier bsaved file */
 
    /* BASIC will use original segment and offset information  */
    /* to reload a memory image unless "DEF SEG" has been used */
    /* and then an explicit offset is used as the second arg   */
    /* of the bload command.  If an offset is specified without*/
    /* first calling DEF SEG, The image will then be loaded to */
    /* the offset specified in the last segment pointed to     */
    /* by the last call to DEF SEG. DEF SEG without args returns */
    /* to DGROUP (the default data segment)                      */
 
    /* if loading a data array like an image fragment */
    /* we would first dimension the array as an integer array */
    /* which allocates memory just like malloc() and by the way */
    /* not like the Dim command works in VB.NET in 2007 */
 
    /* we would normally implement using an array in memory and */
    /* VARSEG and VARPTR to obtain the window for the array's   */
    /* memory location, i.e. override the defaults by windowing */
    /* to the array base using DEF SEG = VARSEG(arrayname(0)) then to    */
    /* fill the array we would use BLOAD arrayname, VARPTR(arrayname(0)) */
    /* using VARPTR to point to the offset from the memory base segment  */
 
    /* remember that this is intel byte order - unsigned short in win32  */
    '\x00', '\xb8',  /* base address     = LSB | MSB original segment    */
    '\x00', '\x00',  /* offset from base = LSB | MSB original offset     */
 
    '\x00', '\x40'   /* data size = LSB | MSB of bytes to be loaded +    */
    };
 
unsigned char PUT_image[16384];
 
unsigned char PUT_tailer[1]={
    '\x1A'                      /* traditionally used by BASIC */
    };                          /* as a terminator */
Example

The following GWBASIC program shows by how easy it was to load and save these in BASIC. It loads an existing image, draws a border around it and saves it.

10 INPUT"PICNAME : ", A$
20 INPUT"border color : ",B$
30 B%=VAL(B$)
40 SCREEN 1
50 DEF SEG=&HB800
55 BLOAD A$
60 LINE (0,0)-(319,199),B%,B
61 LINE (1,1)-(318,198),B%-1,B
62 LINE (2,2)-(317,197),B%,B
63 LINE (3,3)-(316,196),0,B
70 BSAVE A$,0, 16384
80 SYSTEM

XCGA low resolution graphics

The Color Graphics Adapter page elsewhere on Wikipedia calls this mode "The 160×100 16 color mode".

XCGA mode as it was known as in the late 1980s enjoyed a brief notoriety amongst enthusiasts but never served any practical purpose because it was too coarse for even for the primitive graphics of the day.

Even so, computers equipped only with a CGA video adapter were still prevalent, with users who wanted to display graphics in more than the 4 color maximum that CGA graphics offered.

XCGA images were generally created by reducing images produced in higher resolution to a lower resolution facsimile by the use of file conversion software. This was generally done by enthusiasts as more of a novelty than for any real purpose.

BSAVED XCGA Images were usually saved with a .CGX extension.

Memory

The memory on XCGA was a contiguous byte array (just like MCGA mode) and was not interleaved like other CGA graphics modes. It started at memory segment B800 like all CGA video memory, and displaying the first 16000 bytes of the segment.

Header

The BSAVED image header was the same as the other CGA BSAVED headers, but the data length was 16000.

Pixel data

Pixels were in a raw format, arranged in pixel pairs called "big pixels" with 2 bytes per each 2 pixel-color pair stored in a contiguous byte array of 8000 big pixels.

Since XCGA was technically a color text mode, the first byte in a big pixel was actually the top two scanlines of a "text graphics" character in video ROM. As in color text mode the second byte stored the foreground color in the low nibble and the background color in the high nibble. (see Color Graphics Adapter.)

The colors 0-16 correspond to the colors offered in text mode, and also to those offered by the EGA in its 16-color graphic modes.

By selecting the appropriate 2 pixel text block graphics character from the video ROM, even though the technical resolution was 80 x 100, the effective resolution was 160 x 100. Fig. 2 above uses the same graphics character normally used in an XCGA image to display a graphic in standard color text mode

Each scanline was 160 bytes long.

Example

The following QuickBasic source code shows how a low resolution BSAVED Image with 16 Colors was displayed. The commands are the same as displaying BSAVE images in standard CGA graphics or text modes with the addition of setting of registers on the CGA's MC6845 CRT controller.

CGXNAME$ = Command$:                    'get name from Command line
On Error GoTo NoFile

Open CGXNAME$ + ".CGX" For Input As 1:  'make sure it exists
Close

GoSub SetXCGA                           'trigger 160x100x16 mode
DEF SEG = &HB800                        'change DSEG to screen
BLOAD CGXNAME$ + ".CGX", 0              'dump picture to screen
a$ = INPUT$(1)
Screen 2: Screen 0: End                 'restore text mode and exit

NoFile: Beep:
        Print "Cannot find " + CGXNAME$
        End

SetXCGA:

'WARNING: Changing these registers settings may cause a CRASH !

DEF SEG = 0
POKE &H465, 0: OUT &H3D8, 0:
POKE &H466, 0: OUT &H3D9, 0
OUT &H3D4, 0: OUT &H3D5, 113
OUT &H3D4, 1: OUT &H3D5, 80
OUT &H3D4, 2: OUT &H3D5, 90
OUT &H3D4, 3: OUT &H3D5, 10
OUT &H3D4, 4: OUT &H3D5, 127
OUT &H3D4, 5: OUT &H3D5, 6
OUT &H3D4, 6: OUT &H3D5, 100
OUT &H3D4, 7: OUT &H3D5, 112
OUT &H3D4, 8: OUT &H3D5, 2
OUT &H3D4, 9: OUT &H3D5, 1
OUT &H3D4, 10: OUT &H3D5, 32
OUT &H3D4, 11: OUT &H3D5, 0
POKE &H465, 9: OUT &H3D8, 9
Return

EGA VGA specification

BSAVE images using multiple color planes and color registers were not common but they did exist.

Additional program code was needed to save and display these which was more complicated than the average user of the day could easily write'.[3][4] The EGA was relatively expensive, and typically used for high-end workstations; by the time low-cost VGA cards came out fewer users experimented with BASIC, and anyway usually preferred to use the lower-resolution 256-color MCGA mode.

MCGA specification

BSAVE images using 256 colors and color palettes were not common but they did exist.

The MCGA was organized in one contiguous byte array of 64000 bytes each with a value of 0-255, and each representing a pixel. Loading and saving these was virtually the same as the CGA Bsaved format with the difference being that additional program code was needed to save and restore the color palettes.[5]

Two MS-DOS based utilities, PICEm and VGACad, offered saving of BSAVE MCGA images, with the latter also offering a BSAVE-style palette save. VGACad used the file extensions .BLD (BLoaDablePicture) and .PLT.

The color palette was most easily saved with some understanding of the graphics card's registers. If the programmer did put effort into this, it usually was not very long before that understanding extended to more capable languages than BASIC and more advanced graphics formats than the BSAVE format.

Example

The following QuickBASIC program shows how to load these in BASIC. The amount of code is substantially larger than in the CGA equivalent.

DEFINT A-Z
IF COMMAND$="" THEN
   PRINT "USAGE IS MCGVU <filename>
   END
END IF

ON ERROR GOTO ENDER
'parse the file name
TARGET$ = COMMAND$ + " "
I = INSTR(".", TARGET$)
J = INSTR(" ", TARGET$)
IF I < J
    PROOT$ = LEFT$(TARGET$, I-1)
ELSE
    PROOT$ = LEFT$(TARGET$, J-1)
END IF

' The MCGA Image and the Palette were saved outside of here
' Both are in BSAVED format
PCOLOR$=PROOT$ +".BLD"
PNAME$ =PROOT$ +".PLT"

SCREEN 13

'--------------------- Read the palette File ---------------
DIM PCOL%(384)
SEGMENT = VARSEG(PCOL%(0))
OFFSET  = VARPTR(PCOL%(0))
DEF SEG = SEGMENT
BLOAD PCOLOR$,OFFSET

'----------------- initialize the registers ----------------
OUT &H3C8, 0
FOR I = 0 TO 255
    OUT &H3C9, PEEK(OFFSET)     'red
    OUT &H3C9, PEEK(OFFSET+1)   'green
    OUT &H3C9, PEEK(OFFSET+2)   'blue
    OFFSET=OFFSET+3
NEXT I

'------------------- load the image to the screen -----------
DEF SEG = &HA000
BLOAD PNAME$,0

' wait for key press
DEF SEG
A$=INPUT$(1)

ENDER:
  SCREEN 0
  END

IBM PC BSAVE image fragments

GET

Example


'This source code is herewith released by me into the Public Domain.
'Bill Buckels, May 30, 2007
'You have a royalty-free right to use, modify, reproduce and distribute this
'source code and the binaries that it produces in any way you find useful

' This is a corrected and rewritten example based on the QBASIC manual
' Demonstrating GET, BSAVE, PUT and BLOAD.

' Both the GWBASIC manual and the QBASIC manual presented their
' examples in a confusing manner, with too much or too little information.
' The QBASIC manual further complicated the matter with incorrect calculations.

' Here's a less-confusing example with properly calculated values.

' A BASIC Screen Fragment is stored in a byte array
' Preceded with a header giving the image size.
' Header - 4 bytes
' X - width of image in bits - short integer (2 bytes)
' Y - height of image in rasters - short integer (2 bytes)
' Image data - Variable
' Image data is arranged in rasters. Each raster is byte-aligned.

' In the example below, CGA 4-color screen mode is used.
' Rasters are stored at 2 bits per pixel (4 pixels per byte).
' Since the Cube is 101 pixels wide, 26 bytes are required per raster.
' The last 6 bits (3 pixels) of each scanline are unused (padding)
' Since the Cube is 101 rasters high, image data is 26 bytes x 101 = 2626 bytes.
' The Header requires 4 bytes.
' The array size required to store the image is 2630 bytes.
' Since a short integer is 2 bytes in size and since an integer array is
' required to use the GET and PUT commands, an integer array size of 2630/2 =
' 1315 is required for this example.

' Allocate enough memory in an integer array to hold an image fragment
DIM fragment(1315)
fragmentSize = 2630
fragmentName$ = "MAGCUBE.PUT"
SCREEN 1

' Create an image fragment
GOSUB DRAWCUBE

' Transfer the image fragment into the integer array
GET (140, 25)-(240, 125), fragment

' BSAVE
' Point to the fragment array and BSAVE to disk.
DEF SEG = VARSEG(fragment(1))
BSAVE fragmentName$, VARPTR(fragment(1)), fragmentSize
DEF SEG                 ' Restore default BASIC segment.

LOCATE 1, 1: PRINT fragmentName$ + " Saved. Press a key to load."
KeyPress$ = INPUT$(1)
CLS

' BLOAD
' The image fragment's array size is BSaved
' so the BLoad command knows how to re-load it from disk
DEF SEG = VARSEG(fragment(1))
BLOAD fragmentName$, VARPTR(fragment(1))
DEF SEG               ' Restore default BASIC segment.

' Put the fragment on the screen.
' The fragment dimensions that the GET command stored are now in
' the array, so the PUT command knows the width and height to display
PUT (80, 10), fragment
LOCATE 1, 1: PRINT "Press a key to end..."
KeyPress$ = INPUT$(1)

SCREEN 2
SCREEN 0

END

DRAWCUBE:
' Draw a white box.
LINE (140, 25)-(140 + 100, 125), 3, B
' Draw the outline of a magenta cube inside the box.
DRAW "C2 BM140,50 M+50,-25 M+50,25 M-50,25"
DRAW "M-50,-25 M+0,50 M+50,25 M+50,-25 M+0,-50 BM190,75 M+0,50"
RETURN

Specifications Apple II

"Low-resolution" (lo-res) graphics

The Apple II had two "low resolution" (lo-res) graphics screen pages which allowed the simultaneous display of 16 colors at a very coarse resolution (40 x 48). This display mode was really too coarse for "meaningful" graphics display although Apple computer provided an excellent kaleidescope demo called "Rod's Color Pattern" to promote its use. Further, since this area of memory (also shared with the text display) was non-contiguous and the Apple II made use of the "memory holes" at the sides of the display for other purposes like mouse support, it was not practical to "BLoad" previously saved graphics images because they would "clobber" these "memory holes" that may be required for other processes.

"High-resolution" (hi-res) graphics

The Apple II had two "high-resolution" graphics screen pages: "page 1" (occupying the 8 kB of memory beginning at 0x2000) and "page 2" (immediately following at 0x4000). It also had two commonly used "high-resolution" graphics modes: "graphics only" ("pure" graphics mode) and "mixed text and graphics" (only offering a partial display of a graphics image with the bottom 4 lines of the respective text "page 1" or "page 2" at the bottom, leaving only the first 160 lines of the graphics screen visible).

The Apple II "high-resolution" (hi-res) graphics mode could be invoked from AppleSoft BASIC with the HGR and HGR2 commands. HGR enabled hi-res page 1 (occupying the 8 kB of memory beginning at 0x2000) with the bottom 4 lines of text page 1 at the bottom. HGR2 enabled hi-res page 2 (immediately following at 0x4000) with no text area showing. A POKE command could be used to independently enable or disable the text area on either page—though text page 2 was rarely used in BASIC, and BASIC programs normally loaded into its memory.

When ProDOS SYS programs were introduced (written in programming languages other than BASIC; like Assembler, C or Pascal) it was common to use "page 2" graphics only because SYS programs loaded at 0x2000 which conflicted with "page 1".

Resolution

The resolution of an Apple II hi-res graphics screen was 280 pixels x 192 rasters and allowed (on very early Apple II's) up to 4 colors to be displayed simultaneously. The hardware generated color by exploiting the nature of composite color video, essentially fooling the monitor into interpreting color from the pixel positions of an otherwise monochrome bitmap. This frugal design kept the hardware simple, but led to limitations as to what colors could be adjacent to each other on a line. Furthermore, as of the second version of the Apple II (non-plus) motherboard (also very early-on), horizontal groups of 7 pixels could be shifted by one half pixel, allowing 2 more colors (and a redundant white and black). The new colors and the original colors could not coexist within the same 7 pixel group.

Although not invented as a memory saving measure, the Apple II display design allowed a 6 color image to be displayed in only 8K of video memory despite the fact that colors would "bleed" (artifact) into each other if the pixels were incompatibly arranged.

File format

The 8 kB hi-res frame buffer (like all 8-bit Apple II video modes), due to another logic chip conserving idiosyncrasy, was interleaved, and in blocks of 128 bytes, with 8 byte non-displayed "holes" in between. Under Apple DOS all binary files had a header of 4 bytes (2 integers representing the address and length of the save). However, since one of the holes was at the very end of the buffer, it could safely be omitted from the save, keeping the entire package inside of 8 kB (with 4 bytes to spare), which avoided the file taking another 256 byte block just for those 4 bytes of metadata. Under ProDOS the metadata is stored in the directory entry, so is not even an issue.

Various prefixes and suffices (such as "PIC", "HPIC", or "HGR") were used to indicate that the file was a graphics screen save. ProDOS had a special "fotofile" filetype (inherited from Apple SOS) of identical format. Unfortunately awareness of it was low, and few programs supported it.

Rasters (scanlines)

The rasters in an Apple II BSAVED image are not contiguous, nor are they in a simple sequential order. They match the video memory on the Apple II which was relatively complicated, and are arranged as follows:

Each scanline is 40 bytes long. There are 3 parent interleaves of 64 scanlines each. Starting at the beginning of the image file, scanlines are arranged in 128 byte blocks beginning with scanlines 0, 64, and 128 in the first block (see table below). 8 bytes at the end of each block are unused by the image.

Each parent interleaf has 8 child interleaves of 8 scanlines each, with a spacing of 1024 bytes (1K) between sequential scanlines in each of the 3 parent interleaves.

Starting at the beginning of the file and respective of the Apple II's interleaved display, the first 8 of the 128 byte blocks run as shown below. This also represents the first of 8 scanlines in each of the 24 child interleaves, and is effectively a block group. 8 of these block groups are stored in the file, with the scanlines in the table below being incremented by 1 for each subsequent block group sequence of 1024 bytes, totalling 8192 bytes (8K) of graphics image data.

First of 8 Sequential Scanline Block Groups in Apple II BSAVE Image
1024 Bytes (1K)
Block Leaf 1 - Offset 0
40 Bytes
Leaf 2 - Offset 40
40 Bytes
Leaf 3 - Offset 80
40 Bytes
Padding - Offset 120
8 Bytes
Scanlines 1 0 64 128 Unused
Scanlines 2 8 72 136 Unused
Scanlines 3 16 80 144 Unused
Scanlines 4 24 88 152 Unused
Scanlines 5 32 96 160 Unused
Scanlines 6 40 104 168 Unused
Scanlines 7 48 112 176 Unused
Scanlines 8 56 120 184 Unused

Because of the interleaved display and the slow processor speed of the Apple II, when these loaded, a visible "venetian blind" effect was produced creating a "wipe" (fade effect) of the previous graphic if any.

Pixels (colors)

The colors in an Apple II BSAVED image are Black, Green, Violet, Orange, Blue, and White. Pixel color is represented by 2 bits. Although the nominal resolution is 280 x 192, the effective resolution considering colors is really only 140 x 192.

In a 40 byte scanline pixels are stored in an bit array of 280 pixel positions referred to as "columns". The highest bit of each byte is used as a "palette" bit and is not considered a column. The lowest bit represents the first column in the byte. So a scan line beginning with $03 would have the first two pixel positions set as white (with the next 5 pixels black).

If the palette bit in a byte is set, the 4 colors available for the pixels in that byte are black, blue, orange, and white.

If the palette bit is not set, the 4 colors available for the pixels in that byte are black, violet, green, and white

Ignoring the 40 palette bits in a 40 byte scanline, there are 280 columns (bits, pixel positions) but only 140 available pixels. So considering each pixel as being a column pair, with an even and odd column, from left to right starting at column 0, if even is set and odd is not set, the pixel is blue or violet. If even is not set and odd is set, the pixel is orange or green. Any two adjacent columns that are set will be white. This means that white pixels (and black pixels) can be positioned at more places than the other colors, but does not alter the fact that the effective resolution is really only 140 x 192 for an Apple II BSAVED image.

BLOAD example

To BLOAD a previously BSAVED image, use the Apple DOS/ProDOS command:

BLOAD <filename>

The following AppleSoft BASIC program loads a BSAVED Apple II Graphics Screen under Apple DOS 3.3. First it clears the screen, lists a directory, waits for user input (the BSAVED screen name) and then loads the screen and waits for a keypress, and repeats until the user ends the program.

1 REM This source code is herewith released
2 REM by me into the Public Domain.
3 REM Bill Buckels, May 31, 2007
10 TEXT
20 HOME
30 CALL - 1184: CALL 42350
40 PRINT "---------------------------------"
50 PRINT "ABINLOAD(C) APPLEII SCREEN LOADER"
60 PRINT "COPYLEFT BILL BUCKELS 2006"
70 PRINT "ENTER BIN FILE OR BLANK TO END..."
80 PRINT "---------------------------------"
90 INPUT "?"
100 IF BIN$ = "" THEN GOTO 500
110 HGR2
120 PRINT CHR$(4)"BLOAD "BIN$",A$4000"
130 GET A$
140 GOTO 10
500 TEXT
510 CALL - 1184: CALL 42350
520 END

BSAVE example

To BSAVE the HGR screen (starting at memory location $2000, for a length of $1FF8) use the Apple DOS/ProDOS command:

BSAVE <filename>,A$2000,L$1FF8

To BSAVE the HGR2 screen (starting at memory location $4000, for a length of $1FF8) use the Apple DOS/ProDOS command:

BSAVE <filename>,A$4000,L$1FF8

Specifications Commodore 64 and 128

The sample screens shown above were converted from the 4 Color BSAVED Image in Fig. 1. Due to the lower resolutions in both the Commodore's standard native graphics display modes, Fig. 6 sacrifices colors to black and white where needed during conversion resulting in color loss. The colors remain intact when converting to the lower resolution 4 color mode, but some detail is lost.

Graphics

Strictly speaking all the uncompressed Graphics File Formats on the Commodore 64 (C64) and 128 (C128) (and there were many) were in a variation of the BSAVE graphics image format because the Commodore stored all binary files (including Graphics) with a two-byte header which provided the file's originating load address. However, because most of these could not be BLoaded directly into the video areas of the C128 they really are a little too advanced to be considered as BSaved graphics images in the same context as on the IBM-PC and Apple II computers of the same vintage.

C64's did not provide a BSAVE nor a BLOAD command with their version of the Commodore BASIC language (Version 2). It was not until the release of Commodore BASIC 7 on the C128 that the BSAVE and BLOAD commands and the BSAVE graphics image format came into existence on the C128.

C64's BASIC did provide a LOAD command which was intended to LOAD binary program files, data files, and BASIC programs, but this command when used in a C64 BASIC program to load binary data files like BSAVE images needed to restart the BASIC program after the ("non-relocating") load.

This lack of support for loading binary data files from a BASIC program without restarting the program itself amounted to a very serious shortcoming in C64 BASIC Version 2 (later corrected by the C128's BLOAD command) which left the C64 user with the option writing a program that could be restarted after the ("non-relocating") load, or the option of slowly reading binary data files one byte at a time, and then moving the data to memory one byte at a time with data conversion further slowing-down the process.

Technically the standard HIRES graphics mode on the C128 was the same as on the C64 except that the default address in RAM where videoram (HIRES colors) are stored on the C128 directly preceded the default screen address (unlike the C64). This made loading a single BSAVE graphic file in either a monochrome or color format (of the uncompressed type produced by DOODLE) possible on the C128.

Resolution and pixel blocks

The two primary graphics mode resolutions that both the C64 and C128 shared were 320 x 200 (HIRES) and 160 x 200 (Multi-Color Mode). Both modes provided selection of colors from a standard built-in palette of colors.

In HIRES mode, the screen was broken-down in blocks of 8 pixels x 8 scanlines. Pixels of two colors from the 16 color palette could be displayed in each block.

In Multi-Color Mode, the screen was broken down in blocks of 4 pixels x 8 scanlines. Pixels of 4 colors from the 16 color palette could be displayed in each block.

However because only 2 colors could be stored in the standard memory area shared by HIRES mode, a separate area of RAM was used to store the other two colors which was not contiguous with the default screen address and which was fixed (even the C128). This meant that a separate BSAVE file containing the remaining 2 colors was required to BSAVE and BLOAD these on the C128 (keeping in mind that the C64 did not support the BSaved format).

This is somewhat similar to the loading of multiple BSaved files on the IBM PC's EGA, VGA, and MCGA Modes discussed above.

File format

The size of a HIRES Monochrome BSAVE image without the two byte header was 8000 bytes (the same size as visible screen memory), and was "linearized". The many file extensions possible included .HIR and .HBM, if a file extension was used at all.

The size of a HIRES Color BSAVE image (of the uncompressed type produced by DOODLE) was 9024 bytes (the same size as videoram plus visible screen memory) without the two byte header, and was "linearized". The file extension was .DD, if a file extension was used at all.

Other variations of HIRES and even Multi-Color BSaved formats could be produced from compatible graphics formats by splitting them into uncompressed pieces with BLoadable addresses. If a split graphics image was used it was generally split into an 8000 byte bitmap and 1000 byte videoram (2 colors) for HIRES mode, and with a third file, a 1000 byte colorram (2 colors), for Multi-Color Mode.

Like all BIN (Binary) files on the C64 and C128, the files had a binary header of 2 bytes (1 integer). The header gave the load address for the file, and the length was already known to BASIC 7. The default load addresses on the C128 were $2000, $1C00, and $D800 for bitmap, videoram, and colorram respectively.

Generally speaking, the popular uncompressed Multi-Color (4 Color) formats produced by the Paintbrush programs of the day could not be BLoaded without splitting them (in a separate program) and performing an additional operation of putting a background color which was stored elsewhere in the originating file into the 1000 high-nibbles of colorram.

Since the screen address on the C64 and C128 was relocatable, the screen address could be detected and used by the loader program when BLoading these split files.

Rasters (scanlines)

The rasters in a C128 BSAVED image are not contiguous, but are in a simple sequential order of pixel blocks (as noted above). They match the video memory on the C128 which in its standard modes was uncomplicated except for its pixel block orientation.

Because of the slow processor speed of the C128 combined with slow storage access, when a HIRES image loaded it was displayed in 25 passes of 40 chunks creating a choppy effect. If the HIRES image had colors it was often blurry and not recognizable since the colors loaded after the image was already being displayed leaving the user with nothing to do but wait until it was finished.

Pixels (colors)

The standard available colors in a C128 image are BLACK, WHITE, RED, CYAN, PURPLE, GREEN, BLUE, YELLOW, ORANGE, BROWN, LIGHT RED,DARK GREY,MEDIUM GREY,LIGHT GREEN, LIGHT BLUE,and LIGHT GREY. Pixel color is represented by 2 bits in HIRES mode and 4 bits in Multi Color Mode. But as indicated above, not all 16 Colors can be displayed in a pixel block.

BLOAD examples C64

The BLOAD command did not exist on the C64. Instead a BASIC program could use a "non-relocating" LOAD command to load BSAVED Graphics if it was designed to restart after the load, as demonstrated in the following Commodore BASIC 2 program. It loads a colored BSAVED HIRES Graphics Screen on the C64 from 2 separate BSaved Files (a split image), waits for a keypress and ends.

The load address in the 2 files of $2000 for bitmap and $400 for videoram respectively are in the file headers and are used by the LOAD command to read the files directly into the C64's RAM.

Compared to BASIC 7 on the C128 (see C128 examples also below), the C64's BASIC 2 was somewhat less straight-forward.

1 GOTO 500
2 REM This source code is herewith released
3 REM by me into the Public Domain.
4 REM Bill Buckels, October 26, 2008
100 K$=""
110 GET K$
120 IF K$ = "" THEN 110
125 FOR I=8192 TO 16191: POKE I,0: NEXT I
130 POKE 53265, PEEK(53265) AND 223
135 SYS 49152
140 END
500 IF J=1 THEN 600
510 IF J=2 THEN 100
520 POKE 53272,PEEK(53272) OR 8
530 POKE 53265, PEEK(53265) OR 32
540 FOR I = 1024 TO 2047: POKE I,16 : NEXT I
550 B$="ERINLOG.BHI"
560 J=1
570 LOAD B$,8,1
600 V$="ERINLOG.VHI"
610 J=2
620 LOAD V$,8,1

A second (and slower) alternative shown below which does not require a program restart is to open the BSAVED Graphic as a file. The program example below is functionally the same as the one above.

1 REM This source code is herewith released
2 REM by me into the Public Domain.
3 REM Bill Buckels, October 2, 2007
5 POKE 53272,PEEK(53272) OR 8
10 POKE 53265, PEEK(53265) OR 32
20 FOR I = 1024 TO 2047: POKE I,16 : NEXT I
50 OPEN 1,8,2,"ERINLOG.BHI"
51 B$ = CHR$(0)
52 FOR I=1 TO 2:GET #1,A$:NEXT I
54 FOR I=8192 TO 16191
55 GET #1,A$:POKE I,ASC(A$+B$)
56 NEXT I
57 CLOSE 1
60 OPEN 1,8,2,"ERINLOG.VHI"
61 B$ = CHR$(0)
62 FOR I=1 TO 2:GET #1,A$:NEXT I
64 FOR I=1024 TO 2047
65 GET #1,A$:POKE I,ASC(A$+B$)
66 NEXT I
67 CLOSE 1
100 K$=""
110 GET K$
120 IF K$ = "" THEN 110
125 FOR I=8192 TO 16191: POKE I,0: NEXT I
130 POKE 53265, PEEK(53265) AND 223
135 SYS 49152
140 END

BLOAD examples C128

The following Commodore BASIC 7 program loads a BSAVED HIRES Monochrome Graphics Screen on the C128 then sets each of the colors for the 1000 pixel blocks to black and white, waits for a keypress and ends. No colors are stored in the image. The load address in the image is at the start of display memory at $2000.

1 REM This source code is herewith released
2 REM by me into the Public Domain.
3 REM Bill Buckels, August 19, 2007
10 GRAPHIC 1,1
20 BLOAD "ERINLOG.HIR"
24 REM POKE I,16 will reverse video
25 FOR I = 7168 TO 8167:POKE I,1:NEXT I
30 A$=""
40 GET A$
50 IF A$ = "" THEN 40
60 GRAPHIC 0,1
70 END

The following Commodore BASIC 7 program loads a BSAVED HIRES Colored Graphics Screen in DOODLE uncompressed format on the C128, waits for a keypress and ends. The load address in the image is at the start of C128 videoram at $1C00 directly before screen memory at $2000. No color setting is required since the colors are stored in the image and are loaded directly into the C128's HIRES color memory (videoram).

1 REM This source code is herewith released
2 REM by me into the Public Domain.
3 REM Bill Buckels, August 19, 2007
10 GRAPHIC 1,1
20 BLOAD "ERINLOG.DD"
30 A$=""
40 GET A$
50 IF A$ = "" THEN 40
60 GRAPHIC 0,1
70 END

The following Commodore BASIC 7 program loads a BSAVED Multi-Colored 4 Color Graphics Screen in 3 separate BSaved Files (a split image) on the C128, waits for a keypress and ends. The load address in the 3 files are $2000 for bitmap, $1C00 for videoram, and $D800 for colorram respectively. No color setting is required since the colors are stored in the videoram and colorram and are loaded directly into the C128's RAM.

10 GRAPHIC 3,1             :REM  MULTICOLOR GRAPHIC MODE
20 A=PEEK(1): B=PEEK(216)  :REM  SAVE THESE
30 POKE 216,255            :REM  TELL IRQ TO GIVE US VIC CONTROL
40 POKE 1, A AND 252       :REM  SELECT PROCESSOR NYBBLE BANK
50 BLOAD "ERINLOG.BMC"     :REM  LOAD BIT MAP AT $2000
60 BLOAD "ERINLOG.VMC"     :REM  LOAD COLORS 01 AND 10 AT $1C00
70 BLOAD "ERINLOG.CMC"     :REM  LOAD COLORS 11 AT $D800
80 POKE 1,A                :REM  RESTORE SYSTEM NYBBLE BANK
90 POKE 216,B              :REM  RESTORE SYSTEM VIC CONTROL
100 K$ = ""
110 GET K$                 :REM  WAIT FOR A KEYPRESS
120 IF K$ = "" THEN 110
130 GRAPHIC 0,1            :REM  TEXT MODE
140 END

Bitmap converter example

The following C language source code is part of a Windows Program written in Microsoft C and the WIN32 SDK. It demonstrates how a monochrome bitmap in a standard format can be reorganized to display as a BSaved Image on the Commodore 128 (C128).

Programs that convert bitmaps with colors to a C128 HIRES or Multi-Color compatible format use the same basic logic as the example below, with additional logic to organize the color map. Under Windows on the IBM PC these converted images can then be inserted into C128 "disk images" used by C128 emulators and loaded by programs similar to the C128 Basic 7 programs shown above.

// This source code is herewith released by me into the Public Domain.
// Bill Buckels, August 25, 2007
int SaveFragmentToC64(char *name,char *printshopbuffer)
{
 
    // creates a banded C64 image from an 88 x 52 monochrome bitmap
    // ("old printshop" graphic format) which can be bloaded on the C64
    // and centered relative to the default screen address at $2000
    // the image is padded by 4 scanlines on the bottom to adjust
    // for C64 block increments of 8 scanlines.
    // space is padded to both sides of the image to provide a contiguous load
    // and for consistency which results in an image of 320 x 56 in actual size.
    int fh;
 
    unsigned char header[2];
    unsigned char buffer[320];
 
    unsigned x, y, y1, idx, offset, inset;
 
    // create in subdirectory if possible
    _mkdir("c1541");
    _chdir("c1541");
 
#ifndef S_IWRITE
#define S_IWRITE    0000200     // write permission, owner
#endif
 
if((fh = _open(name,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IWRITE)) == -1) {
	    _chdir("..");
        return FAILURE;
	}
 
    // create load address to center on C64 screen
    header[0] = 0x4E;  // offset into screen = 72 x 40 = 2880 + 14 + 8192 ($2000)
    header[1] = 0x2B;
 
     _write(fh,(char *)&header[0],2);
 
    // 14 + 11 + 15 = 40 byte scanline
    // bitmap picture height = 52 scanlines
    // C64 image height = 56 scanlines
 
    // 7 bands of 320 bytes instead of the usual 25
    // each band holds 8 scanlines from the original bitmap
    // except the last one which holds only 4
    for (y = 0; y < 7; y++) {
	    // pad the band with blackspace
	    for (idx = 0; idx < 320; idx++)buffer[idx] = 0;
	    y1 = y * 8 * 11;
	    inset = 8 * 14;
		for (x = 0; x < 11; x++) {
		     for (idx = 0; idx < 8; idx++) {
			offset = y1 + (idx * 11) + x;  // down 8, across 11 times
 
                        if (y == 6 && idx > 3) {
			  // the last band only has 4 rasters
			  // skip reading the last 4
			  inset ++;
			  continue;
		        }
			buffer[inset] = printshopbuffer[offset];
			inset ++;
 
		     }
		}
		// band was created so write it out
		// clip the padding at the top and bottom of the C64 image
		// so it can be optionally loaded anywhere on C64 screen
		// including to top left or bottom right of C64 screen
		if (y == 0) _write(fh,(char *)&buffer[14],(320-14)); // top
		else if (y==6) _write(fh,(char *)&buffer[0],(320-15)); // bottom
		else _write(fh,(char *)&buffer[0],320);
	}
 
     _close(fh);
     _chdir("..");
     return SUCCESS;
 
}

See also

External links

References